diff options
Diffstat (limited to 'app/[lng]/evcp/(evcp)/rfq-last/[id]/layout.tsx')
| -rw-r--r-- | app/[lng]/evcp/(evcp)/rfq-last/[id]/layout.tsx | 112 |
1 files changed, 95 insertions, 17 deletions
diff --git a/app/[lng]/evcp/(evcp)/rfq-last/[id]/layout.tsx b/app/[lng]/evcp/(evcp)/rfq-last/[id]/layout.tsx index 1b058801..999bfe8b 100644 --- a/app/[lng]/evcp/(evcp)/rfq-last/[id]/layout.tsx +++ b/app/[lng]/evcp/(evcp)/rfq-last/[id]/layout.tsx @@ -4,9 +4,12 @@ import { Separator } from "@/components/ui/separator" import { SidebarNav } from "@/components/layout/sidebar-nav" import { formatDate } from "@/lib/utils" import { Button } from "@/components/ui/button" -import { ArrowLeft } from "lucide-react" +import { Badge } from "@/components/ui/badge" +import { ArrowLeft, Clock, AlertTriangle, CheckCircle, XCircle, AlertCircle } from "lucide-react" import { RfqsLastView } from "@/db/schema" import { findRfqLastById } from "@/lib/rfq-last/service" +import { differenceInDays } from "date-fns" +import { Alert, AlertTitle, AlertDescription } from "@/components/ui/alert" export const metadata: Metadata = { title: "견적 목록 상세", @@ -23,30 +26,92 @@ export default async function RfqLayout({ // 1) URL 파라미터에서 id 추출, Number로 변환 const resolvedParams = await params const lng = resolvedParams.lng - const id = resolvedParams.id + const rfqId = parseInt(resolvedParams.id, 10); + + if (!rfqId || isNaN(rfqId) || rfqId <= 0) { + return ( + <div className="p-4"> + <Alert variant="destructive"> + <AlertCircle className="h-4 w-4" /> + <AlertTitle>오류</AlertTitle> + <AlertDescription> + 유효하지 않은 RFQ입니다. + </AlertDescription> + </Alert> + </div> + ); + } + - const idAsNumber = Number(id) // 2) DB에서 해당 협력업체 정보 조회 - const rfq: RfqsLastView | null = await findRfqLastById(idAsNumber) + const rfq: RfqsLastView | null = await findRfqLastById(rfqId) // 3) 사이드바 메뉴 const sidebarNavItems = [ { title: "견적 문서관리", - href: `/${lng}/evcp/rfq-last/${id}`, + href: `/${lng}/evcp/rfq-last/${rfqId}`, }, { title: "RFQ 발송", - href: `/${lng}/evcp/rfq-last/${id}/vendor`, + href: `/${lng}/evcp/rfq-last/${rfqId}/vendor`, }, ] + // Due Date 상태 계산 함수 + const getDueDateStatus = (dueDate: Date | string | null) => { + if (!dueDate) return null; + + const now = new Date(); + const due = new Date(dueDate); + const daysLeft = differenceInDays(due, now); + + if (daysLeft < 0) { + return { + icon: <XCircle className="h-4 w-4" />, + text: `${Math.abs(daysLeft)}일 지남`, + className: "text-red-600", + bgClassName: "bg-red-50" + }; + } else if (daysLeft === 0) { + return { + icon: <AlertTriangle className="h-4 w-4" />, + text: "오늘 마감", + className: "text-orange-600", + bgClassName: "bg-orange-50" + }; + } else if (daysLeft <= 3) { + return { + icon: <AlertCircle className="h-4 w-4" />, + text: `${daysLeft}일 남음`, + className: "text-amber-600", + bgClassName: "bg-amber-50" + }; + } else if (daysLeft <= 7) { + return { + icon: <Clock className="h-4 w-4" />, + text: `${daysLeft}일 남음`, + className: "text-blue-600", + bgClassName: "bg-blue-50" + }; + } else { + return { + icon: <CheckCircle className="h-4 w-4" />, + text: `${daysLeft}일 남음`, + className: "text-green-600", + bgClassName: "bg-green-50" + }; + } + }; + + const dueDateStatus = rfq?.dueDate ? getDueDateStatus(rfq.dueDate) : null; + return ( <> <div className="container py-6"> <section className="overflow-hidden rounded-[0.5rem] border bg-background shadow"> <div className="hidden space-y-6 p-10 pb-16 md:block"> - <div className="flex items-center justify-end mb-4"> + <div className="flex items-center justify-end mb-4"> <Link href={`/${lng}/evcp/rfq-last`} passHref> <Button variant="ghost" className="flex items-center text-primary hover:text-primary/80 transition-colors p-0 h-auto"> <ArrowLeft className="mr-1 h-4 w-4" /> @@ -55,25 +120,38 @@ export default async function RfqLayout({ </Link> </div> <div className="space-y-0.5"> - {/* 4) 협력업체 정보가 있으면 코드 + 이름 + "상세 정보" 표기 */} + {/* 제목 로직 수정: rfqTitle 있으면 사용, 없으면 rfqCode만 표시 */} <h2 className="text-2xl font-bold tracking-tight"> {rfq - ? `${rfq.rfqCode ?? ""} | ${rfq.packageNo ?? ""} | ${rfq.packageName ?? ""}` + ? rfq.rfqTitle + ? `견적 상세 관리 ${rfq.rfqCode ?? ""} | ${rfq.rfqTitle}` + : `견적 상세 관리 ${rfq.rfqCode ?? ""}` : "Loading RFQ..."} </h2> - - <p className="text-muted-foreground"> - RFQ 관리하는 화면입니다. - </p> - <h3>Due Date:{rfq && rfq?.dueDate && <strong>{formatDate(rfq?.dueDate, "KR")}</strong>}</h3> + + {/* <p className="text-muted-foreground"> + RFQ 관리하는 화면입니다. + </p> */} + + {/* Due Date 표시 개선 */} + {rfq?.dueDate && dueDateStatus && ( + <div className="flex items-center gap-3 pt-2"> + <span className="text-sm font-medium text-muted-foreground">Due Date:</span> + <strong className="text-sm">{formatDate(rfq.dueDate, "KR")}</strong> + <div className={`flex items-center gap-1.5 px-2.5 py-1 rounded-full ${dueDateStatus.bgClassName} ${dueDateStatus.className}`}> + {dueDateStatus.icon} + <span className="text-xs font-medium">{dueDateStatus.text}</span> + </div> + </div> + )} </div> <Separator className="my-6" /> <div className="flex flex-col space-y-8 lg:flex-row lg:space-x-12 lg:space-y-0"> - <aside className="lg:w-64 flex-shrink-0"> - <SidebarNav items={sidebarNavItems} /> + <aside className="lg:w-64 flex-shrink-0"> + <SidebarNav items={sidebarNavItems} /> </aside> <div className="lg:w-[calc(100%-16rem)] overflow-auto">{children}</div> - </div> + </div> </div> </section> </div> |
